package com.regentsoft.cloudback.enterpriseAdmin.util;

import com.regentsoft.cloudback.enterpriseAdmin.entity.MediaFile;
import com.regentsoft.cloudback.exception.FileManagerException;
import org.apache.tomcat.util.http.fileupload.util.Streams;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.file.FileSystem;
import java.nio.file.*;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 媒体文件管理器
 * Created by work on 2017/11/28.
 *
 * @author lumr
 */
@Component
public class MediaFileManager implements Closeable {
    private final String ROOTPATH;
    private final Path TEMPPATH;
    private final FileSystem system;
    private final String DEFAULT_PICTURE = "NoPicture.png";
    private final Map<String, Path> tempMap = new ConcurrentHashMap<>();

    @Autowired
    public MediaFileManager(@Value("${media.file.rootpath}") String ROOTPATH) throws IOException {
        this.ROOTPATH = ROOTPATH;
        this.system = FileSystems.getDefault();
        this.TEMPPATH = system.getPath(ROOTPATH, "temp");
        if (Files.notExists(TEMPPATH))
            Files.createDirectory(TEMPPATH);
        Path noPath = system.getPath(ROOTPATH, "media");
        if (Files.notExists(noPath))
            Files.createDirectory(noPath);
        Path noPic = system.getPath(ROOTPATH, "media", DEFAULT_PICTURE);
        if (Files.notExists(noPic)) {
            ClassPathResource resource = new ClassPathResource("public/media/"+DEFAULT_PICTURE);
            try (InputStream is = resource.getInputStream()) {
                Files.copy(is, noPic);
            }
        }

    }

    /**
     * 获取当前目录下所有文件
     *
     * @param companyId
     * @return
     */
    public File[] getAllFileName(String companyId) {
        try {
            Path path = system.getPath(ROOTPATH, companyId);
            return Files.list(path).map(Path::toFile).toArray(File[]::new);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 保存文件
     *
     * @param companyId
     * @param input
     * @param fileName
     * @return
     */
    public boolean save(String companyId, InputStream input, String fileName) {
        Path path = system.getPath(ROOTPATH, companyId, fileName);

        try {
            if (Files.notExists(path.getParent()))
                Files.createDirectory(path.getParent());
            Files.copy(input, path, StandardCopyOption.REPLACE_EXISTING);
            input.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            throw new FileManagerException("保存文件时错误：" + e.getMessage(), e);
        }
    }

    /**
     * 从临时文件保存文件
     *
     * @param companyId
     * @param fileToken
     * @param fileName
     * @return
     */
    public boolean save(String companyId, String fileToken, String fileName) {
        Path path = tempMap.remove(fileToken);

        if (path == null)
            throw new FileManagerException("临时文件不存在");

        try {
            this.save(companyId, Files.newInputStream(path, StandardOpenOption.READ), fileName);
            Files.deleteIfExists(path);
            return true;
        } catch (IOException e) {
            throw new FileManagerException("保存文件时错误：" + e.getMessage(), e);
        }
    }

    /**
     * 保存临时文件
     *
     * @param companyId
     * @param is
     * @param fileToken
     * @return
     */
    public boolean saveTempFile(String companyId, InputStream is, String fileToken) {
        Path path = tempMap.getOrDefault(fileToken, null);
        try {
            if (path == null) {
                path = Files.createTempFile(TEMPPATH, companyId, null);
                tempMap.put(fileToken, path);
            }
            Streams.copy(is, Files.newOutputStream(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.APPEND), true);
            return true;
        } catch (IOException e) {
            throw new FileManagerException("创建temp文件时错误：" + e.getMessage(), e);
        }
    }

    /**
     * 删除文件
     *
     * @param companyId
     * @param fileName
     * @return
     */
    public boolean delete(String companyId, String fileName) {
        Path path = system.getPath(ROOTPATH, companyId, fileName);
        try {
            Files.deleteIfExists(path);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            throw new FileManagerException("删除文件时失败:" + e.getMessage(), e);
        }
    }

    /**
     * 获取文件
     *
     * @param companyId
     * @param fileName
     * @return
     */
    private File getFile(String companyId, String fileName) {
        Path path = system.getPath(ROOTPATH, companyId, fileName);
        return path.toFile();
    }

    private Path getPath(String companyId, String fileName) {
        return system.getPath(companyId, fileName);
    }

    /**
     * 获取全部文件数据
     *
     * @param companyId
     * @param fileName
     * @return
     */
    public MediaFile getFileBytes(String companyId, String fileName) {
        return getFileInputStream(companyId, fileName);
    }

    private MediaFile getFileInputStream(String companyId, String fileName) {
        File file = getFile(companyId, fileName);
        if (!file.exists()) {
            file = getFile("media", DEFAULT_PICTURE);
            fileName = DEFAULT_PICTURE;
        }
        try {
            return new MediaFile(new FileInputStream(file), fileName, file.length());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw new FileManagerException("文件获取失败:" + e.getMessage());
        }
    }

    /**
     * 分段获取文件数据
     *
     * @param companyId
     * @param fileName
     * @param start
     * @param len
     * @return
     */
    public MediaFile getFileBytes(String companyId, String fileName, long start, int len) {
        File file = getFile(companyId, fileName);
        if (!file.exists()) {
            file = getFile("media", DEFAULT_PICTURE);
            fileName = DEFAULT_PICTURE;
            len = (int) file.length();
        }
        try (FileInputStream input = new FileInputStream(file)) {
            byte[] bytes = new byte[len];
            long skiplen = input.skip(start);
            if (skiplen < start)
                return new MediaFile(fileName, bytes, len);
            int readlen = input.read(bytes);
            if (readlen != len)
                return new MediaFile(fileName, bytes, readlen);
            else
                return new MediaFile(fileName, Arrays.copyOf(bytes, readlen), readlen);

        } catch (IOException e) {
            throw new FileManagerException("获取分片文件失败：" + e.getMessage(), e);
        }
    }

    public String copyFileToWeb(String companyId, String fileName) {
        File file = getFile(companyId, fileName);
        if (Files.notExists(file.toPath()))
            return "media/"+DEFAULT_PICTURE;
        return companyId + "/" + fileName;

    }

    @Override
    public void close() throws IOException {
        for (String key : tempMap.keySet()) {
            Files.deleteIfExists(tempMap.get(key));
        }

        try {
            system.close();
        } catch (UnsupportedOperationException e) {
            System.out.println(system.getClass().getSimpleName().concat("不需要关闭。"));
        } catch (Exception e) {
            System.out.println("文件系统关闭失败" + e.getMessage());
        }
    }

}
